package org.dolphin.dao.impl;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.dolphin.dao.AccessControlDao;
import org.dolphin.dao.util.SessionHelper;
import org.dolphin.entity.security.AccessControl;
import org.dolphin.entity.security.Group;
import org.dolphin.entity.security.Url;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.sql.JoinType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository(value = "accessControlDao")
public class AccessControlDaoImpl implements AccessControlDao {
  @Autowired(required = true)
  private SessionFactory sessionFactory;

  @SuppressWarnings("unchecked")
  @Override
  public List<AccessControl> getAccessControls() {
    DetachedCriteria dc = DetachedCriteria.forClass(AccessControl.class);
    Session session = SessionHelper.getCurrentSession(sessionFactory);
    Criteria criteria = dc.getExecutableCriteria(session);
    List<AccessControl> list = criteria.list();
    return list;
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<AccessControl> getAccessControls(Set<Group> groups) {
    if (groups == null || groups.isEmpty()) {
      return Collections.emptyList();
    }
    Set<Long> ids = new HashSet<Long>(groups.size());
    for (Group group : groups) {
      ids.add(group.getId());
    }
    DetachedCriteria subqueryDc = DetachedCriteria.forClass(Group.class);
    subqueryDc.createCriteria("accessControls", "ac", JoinType.INNER_JOIN);
    subqueryDc.add(Restrictions.in("id", ids));
    subqueryDc.setProjection(Projections.projectionList().add(Projections.property("ac.id")));

    DetachedCriteria dc = DetachedCriteria.forClass(AccessControl.class);
    dc.add(Subqueries.propertyEq("id", subqueryDc));
    Session session = SessionHelper.getCurrentSession(sessionFactory);
    Criteria criteria = dc.getExecutableCriteria(session);
    List<AccessControl> list = criteria.list();
    return list;
  }

  @SuppressWarnings("unchecked")
  @Override
  public List<Url> getUrlAccessControls() {
    DetachedCriteria dc = DetachedCriteria.forClass(Url.class);
    dc.createAlias("accessControls", "ac", JoinType.INNER_JOIN);
    dc.addOrder(Order.asc("url"));
    Session session = SessionHelper.getCurrentSession(sessionFactory);
    Criteria criteria = dc.getExecutableCriteria(session);
    List<Url> list = criteria.list();
    if (list != null && !list.isEmpty()) {
      for (Url url : list) {
        Hibernate.initialize(url.getAccessControls());
      }
    }
    return list;
  }
}
